package com.qianfeng.smartdevice.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qianfeng.smartdevice.cache.CategoryCache;
import com.qianfeng.smartdevice.enums.CheckType;
import com.qianfeng.smartdevice.event.SysCategoryCacheChangeEvent;
import com.qianfeng.smartdevice.execption.AddDataErrorException;
import com.qianfeng.smartdevice.execption.DeleteDataErrorException;
import com.qianfeng.smartdevice.execption.MyErrorCode;
import com.qianfeng.smartdevice.execption.UpdateDataErrorException;
import com.qianfeng.smartdevice.mapper.SysCategoryMapper;
import com.qianfeng.smartdevice.pojo.SysCategory;
import com.qianfeng.smartdevice.pojo.SysUserInfo;
import com.qianfeng.smartdevice.service.SysCategoryService;
import com.qianfeng.smartdevice.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by wenka on 2022/3/25 14:13
 *
 * @author Jackiechan
 * @version 1.0
 * @since 1.0
 */
@Service
@Transactional
public class SysCategoryServiceImpl implements SysCategoryService {
    private SysCategoryMapper sysCategoryMapper;
    private ApplicationContext context;
    private CategoryCache categoryCache;

    @Autowired
    public void setCategoryCache(CategoryCache categoryCache) {
        this.categoryCache = categoryCache;
    }

    @Autowired
    public void setContext(ApplicationContext context) {
        this.context = context;
    }

    @Autowired
    public void setSysCategoryMapper(SysCategoryMapper sysCategoryMapper) {
        this.sysCategoryMapper = sysCategoryMapper;
    }

    @Override
    public void addCategory(SysCategory sysCategory) {
        //检查数据是不是传递了
        Assert.isTrue(!sysCategory.isEmpty(CheckType.ADD), () -> {
            throw new AddDataErrorException("传递的数据不能为空", MyErrorCode.DATA_NULL);
        });
        //获取登录用户
        SysUserInfo loginUser = SecurityUtils.getLoginUser();
        //我们要求必须登录
        Assert.notNull(loginUser, () -> {
            throw new AddDataErrorException("未登录", MyErrorCode.NOT_LOGIN);
        });
        SysCategory byCategoryName = sysCategoryMapper.findByCategoryName(sysCategory.getCategoryName());

        Assert.isNull(byCategoryName,()->{
            throw new AddDataErrorException("分类已存在", MyErrorCode.DATA_ALLREADY_EXIST);
        });
        sysCategory.setCreateBy(loginUser.getUsername());
        sysCategory.setCreateTime(new Date());
        sysCategoryMapper.addCategory(sysCategory);
        //通知缓存更新
        context.publishEvent(new SysCategoryCacheChangeEvent());
    }

    @Override
    @Transactional(readOnly = true)
    public SysCategory findByCid(Long cid) {
        //注意，按照我们得要求，id必须大于0
        //从缓存中查询
        SysCategory sysCategory = categoryCache.get(cid);
        return sysCategory;
//        return sysCategoryMapper.findByCid(cid);
    }

    @Override
    public PageInfo<SysCategory> findAll(int pageNum, int pageSize, String categoryName) {
        PageHelper.startPage(pageNum, pageSize);
        //从缓存里获取
        List<SysCategory> categoryListCache = categoryCache.getCategoryListCache();
        //获取名称中的关键字
        List<SysCategory> sysCategoryList = categoryListCache.stream().filter(sysCategory -> {
            //如果里类名里面包含则返回，如过不包含则就返回所有数据
            return StringUtils.hasText(categoryName) ? sysCategory.getCategoryName().contains(categoryName) : true;
        }).collect(Collectors.toList());
        List<SysCategory> categoryList = sysCategoryList.stream().skip((pageNum - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
        PageInfo<SysCategory> pageInfo = new PageInfo<>(categoryList);
        //设置符合条件的所有的数据
        pageInfo.setTotal(sysCategoryList.size());
        pageInfo.setPageSize(pageSize);
        pageInfo.setPageNum(pageNum);
        return pageInfo;
    }

    @Override
    public int updateCategory(SysCategory sysCategory) {
        //如果什么都不传递, 是不能执行更新操作的,需要对数据进行校验
        Assert.isTrue(!sysCategory.isEmpty(CheckType.UPDATE),()->{
            throw new UpdateDataErrorException("数据为空", MyErrorCode.DATA_NULL);
        });

        //必须登录
        //检查当前是不是登录了用户,如何判断用户登录了, 所以一定有个地方保存了登录的用户(数据到底保存在什么地方是我们决定的),我们登录完成后放到session了
        //那我们只需要从session中获取
        SysUserInfo userInfo = SecurityUtils.getLoginUser();
        //我们要求必须登录
        Assert.notNull(userInfo,()->{
            throw new AddDataErrorException("未登陆", MyErrorCode.NOT_LOGIN);
        });
        sysCategory.setUpdateBy(userInfo.getUsername());
        sysCategory.setUpdateTime(new Date());
        int result = sysCategoryMapper.updateCategory(sysCategory);
        sysCategoryMapper.updateCategory(sysCategory);
        //发布一个事件，更新一下缓存
        context.publishEvent(new SysCategoryCacheChangeEvent());
        return result;

    }

    @Override
    public int deleteByIds(List<Long> ids) {
        Assert.notEmpty(ids,()->{
            throw new DeleteDataErrorException("未传递主键", MyErrorCode.DATA_NULL);
        });
        SysUserInfo userInfo = SecurityUtils.getLoginUser();
        //我们要求必须登录
        Assert.notNull(userInfo,()->{
            throw new AddDataErrorException("未登陆", MyErrorCode.NOT_LOGIN);
        });
        int count = sysCategoryMapper.deleteByIds(ids);
        //发布一个事件，更新一下缓存
        context.publishEvent(new SysCategoryCacheChangeEvent());

        return count;
    }
}
